/*
 * Web Crawler
 * Date: November 01, 2011
 * Group JEDi
 * Author(s): James Lovato, Efim Todorasco, Daniel Garrison
 */
package gui;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import multithread.ThreadSafeReporter;
import multithread.ThreadedCrawler;

import singlethread.CrawlerSingleThread;
import singlethread.Reporter;

/**
 * The CrawlerGUI provides CUI for the web crawler
 * 
 * @author James Lovato, Efim Todorasco, Daniel Garrison
 * @version 10/20/11
 */
public class CrawlerGUI implements ActionListener, Observer {

	/**
	 * The default words to count.
	 */
	private static final String WORDS_TO_COUNT = "intelligence, artificial, agent, university, research, science, robot";
	/**
	 * the default sid url.
	 */
	private static final String DEFAULT_URL = "http://faculty.washington.edu/gmobus/";
	/**
	 * The main panel.
	 */
	private final JPanel my_main_panel;
	/**
	 * The single crawler chose radio button.
	 */
	private final JRadioButton my_single_radio_button = new JRadioButton("Single Threaded");
	/**
	 * The number of pages to crawl.
	 */
	private final JTextField my_num_page_text = new JTextField();
	/**
	 * The default words checkbox.
	 */
	private final JCheckBox my_def_words = new JCheckBox("Use default words");
	/**
	 * The default URL checkbox.
	 */
	private final JCheckBox my_def_url = new JCheckBox("Use default URL");
	/**
	 * The text area for words text input.
	 */
	private final JTextArea my_words = new JTextArea();
	/**
	 * The start button.
	 */
	private JButton my_start_button = new JButton("Start >");
	/**
	 * The output text area.
	 */
	private final JTextArea my_output_text = new JTextArea();
	/**
	 * The text field for number of threads.
	 */
	private final JTextField my_thread_text = new JTextField();
	/**
	 * The text field for text input URL.
	 */
	private final JTextField my_url = new JTextField();

	/**
	 * Constructs new CrawlerGUI.
	 */
	public CrawlerGUI() {
		my_main_panel = new JPanel();
		my_main_panel.setBackground(Color.white);
		my_main_panel.setLayout(new BorderLayout());
		JPanel panel1 = choises();
		JPanel panel2 = words();
		JPanel panel3 = console();
		panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createMatteBorder(1,1,1,1, Color.BLACK),"MENU"));
		panel2.setBorder(BorderFactory.createTitledBorder(BorderFactory.createMatteBorder(1,1,1,1, Color.BLACK),"TEXT INPUT"));
		panel3.setBorder(BorderFactory.createTitledBorder(BorderFactory.createMatteBorder(1,1,1,1, Color.BLACK),"OUTPUT"));
		my_main_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		my_main_panel.add(panel1, BorderLayout.NORTH);
		my_main_panel.add(panel2, BorderLayout.CENTER);
		my_main_panel.add(panel3, BorderLayout.SOUTH);
	}
	/**
	 * Provides menu panel.
	 * 
	 * @return menu panel.
	 */
	private JPanel choises(){
		final JRadioButton multi = new JRadioButton("Multi Threaded");
		final JPanel panel1 = new JPanel();
		final JPanel threads = new JPanel(new GridLayout(1,2));
		final JPanel pages = new JPanel(new GridLayout(1,2));
		final JLabel page_label = new JLabel("Number of pages:");
		final JLabel thread_label = new JLabel("Number of threads:");
		final ButtonGroup choise_group = new ButtonGroup();
		
		panel1.setLayout(new  GridLayout(4,1));
		my_num_page_text.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		my_thread_text.addActionListener(this);
		my_num_page_text.addActionListener(this);
		my_single_radio_button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e)
			{
				my_thread_text.setBorder(BorderFactory.createLineBorder(Color.white));
				my_thread_text.setText("");
				my_thread_text.setEnabled(false);
				my_thread_text.setBackground(Color.LIGHT_GRAY);
				thread_label.setForeground(Color.GRAY);
			}
		});
		multi.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e)
			{

				my_thread_text.setBorder(BorderFactory.createLineBorder(Color.BLACK));
				my_thread_text.setEnabled(true);
				my_thread_text.setBackground(Color.WHITE);
				thread_label.setForeground(Color.BLACK);
			}
		});
		pages.add(page_label);
		pages.add(my_num_page_text);
		threads.add(thread_label);
		threads.add(my_thread_text);
		choise_group.add(my_single_radio_button);
		choise_group.add(multi);
		panel1.add(my_single_radio_button);
		panel1.add(multi);
		panel1.add(pages);
		panel1.add(threads);
		my_single_radio_button.doClick();
		return panel1;
	}
	/**
	 * Provides text input panel.
	 * 
	 * @return text input panel.
	 */
	private JPanel words(){
		final JPanel panel1 = new JPanel(new BorderLayout());
		final JPanel panel2 = new JPanel(new BorderLayout());
		final JPanel panel3 = new JPanel(new BorderLayout());
		final JScrollPane scroll_text_area = new JScrollPane(my_words);
		scroll_text_area.setVerticalScrollBarPolicy(
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		scroll_text_area.setPreferredSize(new Dimension(350, 70));

		my_def_words.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				if (my_def_words.isSelected()) {
					my_words.setEnabled(false);
					my_words.setText("");
				} else {
					my_words.setEnabled(true);
				}
			}
		});
		my_def_words.setToolTipText(WORDS_TO_COUNT);
		my_def_url.setToolTipText(DEFAULT_URL);
		my_def_url.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				if (my_def_url.isSelected()) {
					my_url.setEditable(false);
					my_url.setText("");
				} else {
					my_url.setEditable(true);
				}
			}
		});
		my_url.addActionListener(this);
		my_def_words.doClick();
		my_def_url.doClick();
		panel2.add(my_def_url, BorderLayout.NORTH);
		panel2.add(my_url, BorderLayout.SOUTH);
		panel3.add(my_def_words, BorderLayout.NORTH);
		panel3.add(scroll_text_area, BorderLayout.SOUTH);
		panel1.add(panel2, BorderLayout.NORTH);
		panel1.add(panel3, BorderLayout.SOUTH);
		return panel1;
	}
	/**
	 * Provides output panel.
	 * 
	 * @return output panel.
	 */
	private JPanel console(){
		final JPanel output_panel = new JPanel(new BorderLayout());
		my_output_text.setEditable(false);
		my_output_text.setFont(new Font("Courier", Font.PLAIN, 12));
		final JScrollPane scroll_text_area = new JScrollPane(my_output_text);
		scroll_text_area.setVerticalScrollBarPolicy(
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		scroll_text_area.setPreferredSize(new Dimension(400, 300));
		my_start_button.addActionListener(this);
		my_start_button.setActionCommand("start");
		output_panel.add(scroll_text_area, BorderLayout.NORTH);
		output_panel.add(my_start_button, BorderLayout.SOUTH);
		return output_panel;
	}
	/**
	 * Returns array of words to count from the provided string.
	 * 
	 * @param the_words The words.
	 * @return words to count.
	 */
	private String[] wordsToFind(String the_words) {
		String text = the_words.replaceAll("[^\\p{L}]", " ");
		text = text.toLowerCase();    
		final String words[] = text.split("\\s+");
		return words;
	}
	/**
	 * Checks if sid url is valid.
	 * 
	 * @param the_url The sid url.
	 * @return true if url is valid, false otherwise.
	 */
	private boolean checkUrl(String the_url) {
		boolean good_url = true;
		URL test;
		try {
			test = new URL(the_url);
			try {
				test.openConnection().connect();
			} catch (IOException e) {
				good_url = false;
			}
		} catch (MalformedURLException e) {
			good_url = false;
		}

		return good_url;
	}
	/**
	 * Provides frame.
	 */
	private void guiFrame(){
		final JFrame frame = new JFrame("Web Crawler 1.0");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		final CrawlerGUI crawler  = new CrawlerGUI();
		crawler.my_main_panel.setOpaque(true);
		frame.setContentPane(crawler.my_main_panel);
		frame.pack();
		frame.setVisible(true);
	}
	/**
	 * Perform an action on start button or Enter/Return click an input text fields.. 
	 */
	public void actionPerformed(ActionEvent arg0) {
		final String url;
		final String [] words;
		final int page_count;
		final int thread_count;
		my_output_text.setText("");
		my_output_text.setForeground(Color.BLACK);
		my_main_panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		my_start_button.setEnabled(false);
		if (my_def_words.isSelected()) {
			words = wordsToFind(WORDS_TO_COUNT);
		} else {
			words = wordsToFind(my_words.getText());   		
		}
		if (words.length < 11) {
			if (my_def_url.isSelected()) {
				url = DEFAULT_URL;
			} else {
				url = my_url.getText();   		
			}
			if (checkUrl(url)){
				try{
					page_count = Integer.parseInt(my_num_page_text.getText());
					if (my_single_radio_button.isSelected()) {
						try {
							Reporter.reset();
							new CrawlerSingleThread(page_count, words).start(url);
							my_output_text.setText(Reporter.getReport());

						} catch (IOException e1) {
						}
					}
					else {
						try {
							thread_count = Integer.parseInt(my_thread_text.getText());
							ThreadSafeReporter.reset();
							new ThreadedCrawler(page_count, words, thread_count, url, this);
							// System.err.println("ThreadedCrawler started. ");
							// my_output_text.setText(ThreadSafeReporter.getReport());

						} catch (NumberFormatException e3){
							my_output_text.setForeground(Color.RED);
							my_output_text.setText("Enter number of threads as a number");

						}

					}
				} catch (NumberFormatException e2) {
					my_output_text.setForeground(Color.RED);
					my_output_text.setText("Enter number of pages as a number");
					

				}
			} else {
				my_output_text.setForeground(Color.RED);
				my_output_text.setText("Check your URL");
			}
		} else {
			my_output_text.setForeground(Color.RED);
			my_output_text.setText("No more than 10 words");
		}
		my_main_panel.setCursor(null);
		my_start_button.setEnabled(true);

	}
	/**
	 * The main.
	 * @param the_args The arguments.
	 */
	public static void main(String[] the_args){
		new CrawlerGUI().guiFrame();
	}
	/**
	 * Gets an update from the reporter
	 */
	public void update(Observable the_observable, Object the_args) {
		String report = (String) the_args;
		my_output_text.setText(report);		
	}

}
